#ifndef _PHYSICS_H_
#define _PHYSICS_H_

#include <list>
#include "DynamicSphere.h"
#include "Map.h"
#include "Plane.h"
#include "SphereCollisionEvent.h"

using namespace std;

/**
Physics moves objects and checks collisions
*/
class Physics
{
public:	
	Physics();
	virtual ~Physics();

	/**
	creates scene from map
	*/
	void Init(Map *map);

	/**
	simulates physics
	*/
	void Simulate(float time);

	/**
	Adds sphere to scene
	*/
	void AddSphere(DynamicSphere* sphere);

	/**
	sets sphere for cammera, that collides with terrain, but not with spheres
	*/
	void SetCameraSphere(DynamicSphere* sphere);

	/**
	checkes if simplified ray with thickness (set of boxes) collides with terrain

	return value:
	true if is collision
	folse is is no collision
	*/
	bool IsCollidingSetOfBoxes(Vector3 &a, Vector3 &b, float size);

	/**
	returns current count of spheres in scene
	*/
	int GetSpheresCount();

	/**
	returns number of spheres in virtual map. Used for debugging
	*/
	int GetSphereMapCount();

	/**
	returns the thickness of border
	*/
	int Border(void);

	/**
	sets collision handler for sphere with sphere collision
	*/
	void SetCollisionHandler(SphereSphereCollisionEvent *handler);

	/**
	Removes sphere from scene
	*/
	void RemoveSphere(DynamicSphere *sphere);
		
private:
	SphereSphereCollisionEvent *collisionHandler;
	list<DynamicSphere*>* sphereMap;
	Map *terrainMap;
	int mapX, mapY, mapZ;
	Plane boundingPlanes[6];
	list<DynamicSphere*> spheres;
	int borderWidth;
	float touchDistanceMultiplyer;
	static float epsilon; 

	list<DynamicSphere*>* SphereMap(float x, float y, float z);
	DynamicSphere *cameraSphere;
	void MaintainBoundingBoxCollision(DynamicSphere *sphere);
	bool MaintainBoxCollision(DynamicSphere *sphere, Box *box);
	Vector3 GetBoundedVelocity(Vector3 &normal, Vector3 &velocity);
	Vector3 GetTouchPosition(Vector3 &mirrorNormal, Vector3 &mirrorPoint, Vector3 &point);
	void BoxMaintainVertexCollision(Vector3& vertex, DynamicSphere* sphere);
	void BoxMaintainEdgeCollision(Vector3& edgePoint, Vector3& edgeDirection, DynamicSphere* sphere);
	void MaintainSphereCollision(DynamicSphere* sphere, list<DynamicSphere*> *firstField);
	bool SphereMaintainSphereCollision(DynamicSphere* sphere, DynamicSphere* secondSphere);
	bool IsInsideScene(float x, float y, float z);	
	bool BoxIsBoxColliding(Box* box, Vector3 &position, float size);
	bool BoxIsPlaneColliding(Plane* plane, Vector3 &position, float size);

	void SafeSphereRelocate(DynamicSphere* sphere, list<DynamicSphere*> *sourceList, list<DynamicSphere*> *destinationList);
	bool EnsureOnList(DynamicSphere* sphere, list<DynamicSphere*> *source);
};

#endif